package se.webbzon.boltzmann.game.object.action;

import java.awt.Color;

import se.webbzon.boltzmann.effect.ShakeEffect;
import se.webbzon.boltzmann.environment.AbstractEnvironment;
import se.webbzon.boltzmann.game.environment.GameEnvironment;
import se.webbzon.boltzmann.game.object.item.GameItem;
import se.webbzon.boltzmann.game.object.pickup.Loot;
import se.webbzon.boltzmann.game.object.pickup.MathNote;
import se.webbzon.boltzmann.game.object.pickup.Pickup;
import se.webbzon.boltzmann.game.object.pickup.PickupEnum;
import se.webbzon.boltzmann.game.object.player.AbstractPlayerCharacter;
import se.webbzon.boltzmann.game.region.RegionObject;
import se.webbzon.boltzmann.item.ItemGroup;
import se.webbzon.boltzmann.player.PlayerLevel;
import se.webbzon.boltzmann.sound.SoundUtils;
import se.webbzon.boltzmann.timer.Timer;
import se.webbzon.boltzmann.timer.TimerListener;
import se.webbzon.oschi01.utilities.ArrayUtils;
import se.webbzon.oschi01.worldarea.WorldArea;
import se.webbzon.oschi01.worldeditor.DeflatableWorldObject;
import se.webbzon.oschi01.worldeditor.WorldObjectDeflation;
import se.webbzon.oschi01.worldobject.WorldStaticObject;

public class ShakeAction extends AbstractAction<WorldStaticObject> implements DeflatableWorldObject, RegionObject {
	
	// The name of the deflatable world object
	public static final String worldObjectName = "shakeAction";
	
	// The id of this instance
	private long id;
	
	// Whatever this action is region or game persistent
	private boolean regionPersistent, gamePersistent;
	
	// The loot of this shake action
	private ShakeActionLoot loot;
	
	// The amount of loot (or item id)
	private int amount;
	
	// The timer listener of this action
	private TimerListener listener;
	
	/*============================================================
	Constructors
	============================================================*/

	/** Creates a new sequence action. **/
	public ShakeAction(	AbstractEnvironment env,
						WorldStaticObject parent, 
						boolean frontOnly, double range, long id) {
		super(0, env, parent, Color.green, frontOnly, range);
		this.id = id;
		regionPersistent = false;
		gamePersistent = false;
		loot = ShakeActionLoot.NONE;
		amount = 0;
		listener = new TimerListenerImpl();
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Returns true if this shake action is region persistent. **/
	public boolean isRegionPersistent() {
		return regionPersistent;
	}

	/** Sets whatever this shake action is region persistent. **/
	public void setRegionPersistent(boolean regionPersistent) {
		this.regionPersistent = regionPersistent;
	}

	/** Returns true if this shake action is game persistent. **/
	public boolean isGamePersistent() {
		return gamePersistent;
	}

	/** Sets whatever this shake action is game persistent. **/
	public void setGamePersistent(boolean gamePersistent) {
		this.gamePersistent = gamePersistent;
	}

	/** Returns the loot of this shake action. **/
	public ShakeActionLoot getLoot() {
		return loot;
	}

	/** Sets the loot of this shake action. **/
	public void setLoot(ShakeActionLoot loot) {
		this.loot = loot;
	}

	/** Returns the amount (or item id) dropped by this shake action. **/
	public int getAmount() {
		return amount;
	}

	/** Sets the amount (or item id) dropped by this shake action. **/
	public void setAmount(int amount) {
		this.amount = amount;
	}
	
	@Override public long getId() {
		return id;
	}

	@Override public void setId(long id) {
		this.id = id;
	}
	
	@Override public void onCreate(WorldArea world) {
		super.onCreate(world);
	}
	
	@Override public void onDestroy(WorldArea world) {
		super.onDestroy(world);
	}
	
	@Override public void onActionBegin(WorldStaticObject parent,
										AbstractPlayerCharacter player) {
		WorldArea world = getWorld();
		AbstractEnvironment env = getEnvironment();
		player.setFacing(this);
		
		// Create shake effect. 
		new ShakeEffect(getParent()).launch(world);
		Timer timer = new Timer(30);
		timer.addListener(listener);
		timer.start(world);
		
		// Play sounds
		SoundUtils.playSound(ArrayUtils.random("shake_01","shake_02","shake_03"));
		
		if (hasPersistence(env))
			return;
		
		if (loot == ShakeActionLoot.ITEM) {
			long id = isGamePersistent() ? getId() : 0;
			GameItem item = new GameItem(env,id,ItemGroup.instance().getItem(amount).clone());
			world.createInstance(createLoot(item));
		} else for (int i = 0; i < amount; i++){
			final WorldStaticObject instance;
			switch (loot) {
			case HEALTH:
				instance = new Pickup(env,0,PickupEnum.HEALTH);
				break;
			case ENERGY:
				instance = new Pickup(env,0,PickupEnum.ENERGY);
				break;
			case SILVER_COIN:
				instance = new Pickup(env,0,PickupEnum.SILVER_COIN);
				break;
			case GOLD_COIN:
				instance = new Pickup(env,0,PickupEnum.GOLD_COIN);
				break;
			case NOTE:
				instance = new MathNote(env,0,PlayerLevel.topLevel);
				break;
			default:
				instance = null;
			}
			
			if (instance != null) {
				world.createInstance(createLoot(instance));
			
				// Register persistences
				if (env instanceof GameEnvironment) {
					GameEnvironment genv = (GameEnvironment) env;
					if (isGamePersistent())
						genv.addGamePersistence(this);
					if (isRegionPersistent())
						genv.addRegionPersistence(this);
				}
			}
		}
	}

	@Override public String getName() {
		return worldObjectName;
	}

	@Override public WorldObjectDeflation getDeflation() {
		return new ShakeActionDeflation(0,this);
	}
	
	/*============================================================
	Private Methods
	============================================================*/
	
	/** Creates a loot of the provided instance. **/
	private final Loot createLoot(WorldStaticObject instance) {
		instance.setPosition(	getParent().getX(), 
								getParent().getY() - (getParent().getHeight() - instance.getHeight())/2, 
								getParent().getZ());
		Loot loot = new Loot(instance);
		loot.setVelocity(-1 + 2 * Math.random(), 0, 1 + Math.random());
		return loot;
	}
	
	/** Returns true if the shake action has any persistences. **/
	private boolean hasPersistence(AbstractEnvironment env) {
		if (env.isDebugMode())
			return false;
		else if (env instanceof GameEnvironment) {
			GameEnvironment genv = (GameEnvironment) env;
			return (genv.hasRegionPersistence(this) && regionPersistent) ||
					(genv.hasGamePersistence(this) && gamePersistent);
		} else
			return false;
	}
	
	/*============================================================
	Private Classes
	============================================================*/
	
	private final class TimerListenerImpl implements TimerListener {

		@Override public void onAlarm(Timer timer, WorldArea world) {
			ShakeAction.this.setActive(true);
		}
		
	}

}
